package com.epoch.base.util;

import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.lang3.StringUtils;
/**
 * 校验的类
* <p>Title: DataValidator.java</p>  
* <p>Description: </p>  
* @author 张清磊
* @QQ 544188838
* @date 2018年10月8日
 */
public class DataValidator {
	
    private boolean pass = true;
    private final List<String> errMsgs = new ArrayList<String>();

    /**
     * 检查指定对象是否为“空内容”<br>
     * “空内容”是指对象没有实际值，null引用、空字符串、空集合、空Map、空数组都属于“空内容”
     * @param obj 要检查的对象
     * @return 目标对象为“空内容”时返回<code>true</code>，否则返回<code>false</code>
     */
    public static boolean isEmpty(Object obj) {
        boolean result = false;
        if (obj == null || "".equals(obj)) {
            result = true;
        } else {
            if (obj instanceof Iterable) {
                result = !((Iterable<?>)obj).iterator().hasNext();
            } else if (obj instanceof Map) {
                result = ((Map<?, ?>)obj).isEmpty();
            } else if (obj.getClass().isArray()) {
                result = Array.getLength(obj) == 0;
            }
        }
        return result;
    }

    /**
     * 检查指定对象是否为“空白值”<br>
     * “空白值”是指对象为“空内容”或空白字符串(空格、制表符、换行符等不可见字符组成的字符串)
     * @param obj 要检查的对象
     * @return 目标对象为“空白值”时返回<code>true</code>，否则返回<code>false</code>
     */
    public static boolean isBlank(Object obj) {
        boolean result = false;
        if (DataValidator.isEmpty(obj)) {
            result = true;
        } else if (obj instanceof CharSequence) {
            result = StringUtils.isBlank((CharSequence)obj);
        }
        return result;
    }

    /**
     * 检查指定字符串是否超过指定长度
     * @param str 要检查的字符串
     * @param len 指定长度限制
     * @return 目标字符串长度超过指定限制时返回<code>true</code>，否则返回<code>false</code>
     */
    public static boolean isOverLength(String str, int len) {
        return str != null && str.length() > len;
    }

    /**
     * 检查指定对象是否为整数值
     * @param obj 要检查的对象
     * @return 目标对象为整数(Java内置整数类型，如Integer,Long,BigInteger等)或可被转换为整数(Long)时返回<code>true</code>，否则返回<code>false</code>
     */
    public static boolean isInteger(Object obj) {
        boolean result = false;
        if (DataValidator.isJavaIntType(obj)) {
            result = true;
        } else if (obj instanceof BigDecimal) {
            try {
                ((BigDecimal)obj).longValueExact();
                result = true;
            } catch (ArithmeticException e) {
                e.getClass();
            }
        } else if (obj instanceof Double) {
            result = DataValidator.isInteger(new BigDecimal(((Double)obj).toString()));
        } else if (obj instanceof Short) {
            result = DataValidator.isInteger(new BigDecimal(((Short)obj).toString()));
        } else if (obj instanceof String) {
            try {
                Long.parseLong((String)obj);
                result = true;
            } catch (NumberFormatException e) {
                e.getClass();
            }
        }
        return result;
    }

    /**
     * 检查指定对象是否为数字值
     * @param obj 要检查的对象
     * @return 目标对象为数字(Number)或可被转换为数字(BigDecimal)时返回<code>true</code>，否则返回<code>false</code>
     */
    public static boolean isNumber(Object obj) {
        boolean result = false;
        if (obj instanceof Number) {
            result = true;
        } else if (obj instanceof String) {
            try {
                new BigDecimal((String)obj);
                result = true;
            } catch (NumberFormatException e) {
                e.getClass();
            }
        }
        return result;
    }

    /**
     * 检查指定对象是否为日期值
     * @param obj 要检查的对象
     * @return 目标对象为日期(Date)或符合格式"yyyy-MM-dd"的字符串时返回<code>true</code>，否则返回<code>false</code>
     */
    public static boolean isDate(Object obj) {
        boolean result = false;
        if (obj instanceof Date) {
            result = true;
        } else if (obj instanceof String) {
            result = ((String)obj).matches(GlobelConstant.REGEX_NORMAL_DATE);
        }
        return result;
    }

    /**
     * 检查指定对象是否为日期时间值
     * @param obj 要检查的对象
     * @return 目标对象为日期(Date)或符合格式"yyyy-MM-dd HH:mm:ss"的字符串时返回<code>true</code>，否则返回<code>false</code>
     */
    public static boolean isDatetime(Object obj) {
        boolean result = false;
        if (obj instanceof Date) {
            result = true;
        } else if (obj instanceof String) {
            result = ((String)obj).matches(GlobelConstant.REGEX_NORMAL_DATETIME);
        }
        return result;
    }

    /**
     * 检查指定对象是否大于指定值
     * @param obj 要检查的对象
     * @param limit 指定的上限值
     * @return 目标对象大于指定值时返回<code>true</code>，否则返回<code>false</code>
     */
    public static <E> boolean isBigger(Comparable<E> obj, E limit) {
        return obj != null && limit != null && obj.compareTo(limit) > 0;
    }

    /**
     * 检查指定对象是否小于指定值
     * @param obj 要检查的对象
     * @param limit 指定的下限值
     * @return 目标对象小于指定值时返回<code>true</code>，否则返回<code>false</code>
     */
    public static <E> boolean isSmaller(Comparable<E> obj, E limit) {
        return obj != null && limit != null && obj.compareTo(limit) < 0;
    }

    /**
     * 检查指定对象是否在指定范围内
     * @param obj 要检查的对象
     * @param start 指定范围下限
     * @param end 指定范围上限
     * @return 目标对象在指定范围内时(大于等于下限且小于等于上限)返回<code>true</code>，否则返回<code>false</code>
     */
    public static <E> boolean isBetween(Comparable<E> obj, E start, E end) {
        return obj != null && start != null && end != null && obj.compareTo(start) >= 0 && obj.compareTo(end) <= 0;
    }

    /**
     * 校验指定对象是否为“空内容”，并追加错误提示消息<br>
     * “空内容”是指对象没有实际值，null引用、空字符串、空集合、空Map、空数组都属于“空内容”
     * @param obj 要检查的对象
     * @param errMsg 校验失败的错误提示消息
     * @return 目标对象为“空内容”时校验失败，返回<code>false</code>，否则返回<code>true</code>
     */
    public boolean validateEmpty(Object obj, String errMsg) {
        boolean valid = true;
        if (DataValidator.isEmpty(obj)) {
            valid = false;
            this.addErrMsg(errMsg);
        }
        return valid;
    }

    /**
     * 校验指定对象是否为“空白值”，并追加错误提示消息<br>
     * “空白值”是指对象为“空内容”或空白字符串(空格、制表符、换行符等不可见字符组成的字符串)
     * @param obj 要检查的对象
     * @param errMsg 校验失败的错误提示消息
     * @return 目标对象为“空白值”时校验失败，返回<code>false</code>，否则返回<code>true</code>
     */
    public boolean validateBlank(Object obj, String errMsg) {
        boolean valid = true;
        if (DataValidator.isBlank(obj)) {
            valid = false;
            this.addErrMsg(errMsg);
        }
        return valid;
    }

    /**
     * 校验指定字符串是否超过指定长度，并追加错误提示消息
     * @param str 要检查的字符串
     * @param len 指定长度限制
     * @param errMsg 校验失败的错误提示消息
     * @return 目标字符串长度超过指定限制时校验失败，返回<code>false</code>，否则返回<code>true</code>
     */
    public boolean validateLength(String str, int len, String errMsg) {
        boolean valid = true;
        if (DataValidator.isOverLength(str, len)) {
            valid = false;
            this.addErrMsg(errMsg);
        }
        return valid;
    }

    /**
     * 校验指定对象是否为整数值(null可通过校验)，并追加错误提示消息
     * @param obj 要检查的对象
     * @param errMsg 校验失败的错误提示消息
     * @return 目标对象不是整数(Java内置整数类型，如Integer,Long,BigInteger等)或无法转换为整数时校验失败，返回<code>false</code>，否则返回<code>true</code>
     */
    public boolean validateInteger(Object obj, String errMsg) {
        boolean valid = true;
        if (obj != null && !DataValidator.isInteger(obj)) {
            valid = false;
            this.addErrMsg(errMsg);
        }
        return valid;
    }

    /**
     * 校验指定对象是否为数字值(null可通过校验)，并追加错误提示消息
     * @param obj 要检查的对象
     * @param errMsg 校验失败的错误提示消息
     * @return 目标对象不是数字(Number)或无法转换为数字时校验失败，返回<code>false</code>，否则返回<code>true</code>
     */
    public boolean validateNumber(Object obj, String errMsg) {
        boolean valid = true;
        if (obj != null && !DataValidator.isNumber(obj)) {
            valid = false;
            this.addErrMsg(errMsg);
        }
        return valid;
    }

    /**
     * 校验指定对象是否为日期值(null可通过校验)，并追加错误提示消息
     * @param obj 要检查的对象
     * @param errMsg 校验失败的错误提示消息
     * @return 目标对象不是日期(Date)或不是符合格式"yyyy-MM-dd"的字符串时校验失败，返回<code>false</code>，否则返回<code>true</code>
     */
    public boolean validateDate(Object obj, String errMsg) {
        boolean valid = true;
        if (obj != null && !DataValidator.isDate(obj)) {
            valid = false;
            this.addErrMsg(errMsg);
        }
        return valid;
    }

    /**
     * 校验指定对象是否为日期时间值(null可通过校验)，并追加错误提示消息
     * @param obj 要检查的对象
     * @param errMsg 校验失败的错误提示消息
     * @return 目标对象不是日期(Date)或不是符合格式"yyyy-MM-dd HH:mm:ss"的字符串时校验失败，返回<code>false</code>，否则返回<code>true</code>
     */
    public boolean validateDatetime(Object obj, String errMsg) {
        boolean valid = true;
        if (obj != null && !DataValidator.isDatetime(obj)) {
            valid = false;
            this.addErrMsg(errMsg);
        }
        return valid;
    }

    /**
     * 检验指定对象是否大于指定值(null可通过校验)，并追加错误提示消息
     * @param obj 要检查的对象
     * @param limit 指定的上限值
     * @param errMsg 校验失败的错误提示消息
     * @return 目标对象不大于指定值时校验失败，返回<code>false</code>，否则返回<code>true</code>
     */
    public <E> boolean validateBigger(Comparable<E> obj, E limit, String errMsg) {
        boolean valid = true;
        if (obj != null && limit != null && !DataValidator.isBigger(obj, limit)) {
            valid = false;
            this.addErrMsg(errMsg);
        }
        return valid;
    }

    /**
     * 检验指定对象是否不大于指定值(null可通过校验)，并追加错误提示消息
     * @param obj 要检查的对象
     * @param limit 指定的上限值
     * @param errMsg 校验失败的错误提示消息
     * @return 目标对象大于指定值时校验失败，返回<code>false</code>，否则返回<code>true</code>
     */
    public <E> boolean validateNotBigger(Comparable<E> obj, E limit, String errMsg) {
        boolean valid = true;
        if (obj != null && limit != null && DataValidator.isBigger(obj, limit)) {
            valid = false;
            this.addErrMsg(errMsg);
        }
        return valid;
    }

    /**
     * 检验指定对象是否小于指定值(null可通过校验)，并追加错误提示消息
     * @param obj 要检查的对象
     * @param limit 指定的下限值
     * @param errMsg 校验失败的错误提示消息
     * @return 目标对象不小于指定值时校验失败，返回<code>false</code>，否则返回<code>true</code>
     */
    public <E> boolean validateSmaller(Comparable<E> obj, E limit, String errMsg) {
        boolean valid = true;
        if (obj != null && limit != null && !DataValidator.isSmaller(obj, limit)) {
            valid = false;
            this.addErrMsg(errMsg);
        }
        return valid;
    }

    /**
     * 检验指定对象是否不小于指定值(null可通过校验)，并追加错误提示消息
     * @param obj 要检查的对象
     * @param limit 指定的下限值
     * @param errMsg 校验失败的错误提示消息
     * @return 目标对象小于指定值时校验失败，返回<code>false</code>，否则返回<code>true</code>
     */
    public <E> boolean validateNotSmaller(Comparable<E> obj, E limit, String errMsg) {
        boolean valid = true;
        if (obj != null && limit != null && DataValidator.isSmaller(obj, limit)) {
            valid = false;
            this.addErrMsg(errMsg);
        }
        return valid;
    }

    /**
     * 检验指定对象是否在指定范围内(null可通过校验)，并追加错误提示消息
     * @param obj 要检查的对象
     * @param start 指定的范围下限值
     * @param end 指定的范围上限值
     * @param errMsg 校验失败的错误提示消息
     * @return 目标对象不在指定范围内时(不满足大于等于下限且小于等于上限)校验失败，返回<code>false</code>，否则返回<code>true</code>
     */
    public <E> boolean validateBetween(Comparable<E> obj, E start, E end, String errMsg) {
        boolean valid = true;
        if (obj != null && start != null && end != null && !DataValidator.isBetween(obj, start, end)) {
            valid = false;
            this.addErrMsg(errMsg);
        }
        return valid;
    }

    /**
     * 对校验器追加错误提示消息<br>
     * 追加错误提示消息后会将校验器校验通过状态置为<code>false</code>
     * @param errMsg 要追加的错误提示消息
     */
    public void addErrMsg(String errMsg) {
        this.pass = false;
        this.appendMsg(errMsg);
    }

    /**
     * 获取当前校验器全部的错误提示消息
     * @return 当前校验器全部错误提示消息
     */
    public List<String> getErrMsgs() {
        return new ArrayList<String>(this.errMsgs);
    }

    /**
     * 返回校验器当前校验通过状态
     * @return 当前校验器校验通过状态，<code>true</code>表示校验通过，<code>false</code>表示校验失败
     */
    public boolean isPass() {
        return this.pass;
    }

    /**
     * 重置校验器，重置后校验通过状态复位为<code>true</code>，并清空错误消息
     */
    public void reset() {
        this.pass = true;
        this.errMsgs.clear();
    }

    private void appendMsg(String msg) {
        this.errMsgs.add(msg);
    }

    private static boolean isJavaIntType(Object obj) {
        if (obj instanceof Integer) {
            return true;
        }
        if (obj instanceof Long) {
            return true;
        }
        if (obj instanceof Short) {
            return true;
        }
        if (obj instanceof Byte) {
            return true;
        }
        if (obj instanceof BigInteger) {
            return true;
        }
        if (obj instanceof AtomicInteger) {
            return true;
        }
        if (obj instanceof AtomicLong) {
            return true;
        }
        return false;
    }
}
